<template>
  <a-modal
    :title="title"
    width="80%"
    v-model:open="visible"
    :confirmLoading="confirmLoading"
    :keyboard="false"
    :maskClosable="false"
  >
    <template #footer>
      <a-button key="back" @click="close">
        取消
      </a-button>
      <a-button key="submit" type="primary" :loading="loading" @click="handleOk">
        确定
      </a-button>
    </template>
    <a-spin :spinning="confirmLoading">
      <div >
        <a-form ref="formRef" :model="main" :rules="formRules">
          <a-row :getter="24">
            <a-col :span="6">
              <a-form-item :label="labelDict['bill_date']" :name="'bill_date'" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-date-picker v-model:value="main.bill_date" :value-format="dateFormat" @change="dtChange"/>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['bill_no']" name="bill_no" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input v-model:value="main.bill_no" @change.prevent="loadExistData" ></a-input>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['bill_type']" name="bill_type" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-select v-model:value="main.bill_type" @change="checkCreateOrUpdate">
                    <a-select-option v-for="(v,k,i) in dictProperties['bill_type']" :key="k" :value="parseInt(k)">
                      {{v}}
                    </a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['id_trade_partner']" name="id_trade_partner" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-select allowClear showSearch
                          :filter-option="false"
                          @search="(value) => searchTextForTraders=value"
                          :options="customizedFilterOptions(searchTextForTraders, filteredTradObj)"
                          v-model:value="main.id_trade_partner">
                </a-select>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['departure_port']" name="departure_port" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-select v-model:value="main.departure_port" showSearch>
                  <a-select-opt-group v-for="(item, key, index) in portFiltered(1)" :key="index" :label="key">
                    <a-select-option v-for="i of item" :key="i.code" :value="i.code">
                      {{i.city}}({{i.code}})
                    </a-select-option>
                  </a-select-opt-group>
                </a-select>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['destination_port']" name="destination_port" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-select v-model:value="main.destination_port" showSearch>
                  <a-select-opt-group v-for="(item, key, index) in portFiltered(2)" :key="index" :label="key">
                    <a-select-option v-for="i of item" :key="i.code" :value="i.code">
                      {{i.city}}({{i.code}})
                    </a-select-option>
                  </a-select-opt-group>
                </a-select>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['flight_no']" name="flight_no" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input v-model:value="main.flight_no"></a-input>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['articles']" name="articles" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input v-model:value="main.articles"></a-input>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['weight']" name="weight" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input v-model:value="main.weight"></a-input>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['weight_for_fee']" name="weight_for_fee" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input v-model:value="main.weight_for_fee"></a-input>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['unit_price']" name="unit_price" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input v-model:value="main.unit_price"></a-input>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['status']" name="status" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-select :disabled="!isAdmin" v-model:value="main.status">
                  <a-select-option v-for="(v,k,i) in dictProperties['status']" :key="k" :value="parseInt(k)">
                    {{v}}
                  </a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
          </a-row>
          <a-row :getter="24">
            <a-col :span="6" v-for="item of main.feeItems" :key="item.code">
              <a-row :getter="24">
                  <a-col :span="item.code === 'freight'?23:24">
                    <a-form-item :label="item.name" :name="['feeData',item.code]" :labelCol="labelCol" :wrapperCol="wrapperCol">
                      <a-input @dblclick="computeFreight" v-model:value="main.feeData[item.code].amount" v-on:keyup.enter="computeFreight"></a-input>
                    </a-form-item>
                  </a-col>
                  <a-col :span="1" v-if="item.code === 'freight'">
                    <a-popover placement="leftTop">
                      <template #content>
                        <p>双击/Enter会自动计算结果；公式=计费重量*单价</p>
                      </template>
                      <template #title>
                        <span>提示</span>
                      </template>
                      <QuestionCircleOutlined/>
                    </a-popover>
                  </a-col>
              </a-row>
            </a-col>
          </a-row>
          <a-row :getter="24">
            <a-col :span="6">
              <a-form-item :label="labelDict['total_amount']" name="total_amount" :labelCol="labelCol" :wrapperCol="wrapperCol">
              <a-input-search v-model:value="main.total_amount" @dblclick="autoCompute" @search="autoCompute" enter-button="自动计算">
              </a-input-search>
              </a-form-item>
            </a-col>
            <a-col :span="6">
              <a-form-item :label="labelDict['id_company']" name="id_company" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-select allowClear v-model:value="main.id_company" :options="companies"/>
              </a-form-item>
            </a-col>
          </a-row>
          <a-row :getter="24">
            <a-col :span="10">
              <a-form-item :label="labelDict['memo']" name="memo" :labelCol="labelCol2" :wrapperCol="wrapperCol">
                  <a-textarea v-model:value="main.memo" :autoSize="{ minRows: 3, maxRows: 6 }" showCount :maxlength="150" />
              </a-form-item>
            </a-col>
          </a-row>
        </a-form>
      </div>
    </a-spin>
  </a-modal>
</template>

<script setup>
import moment from 'moment'
import {pick, omit, debounce} from "lodash";
import { postAction, getAction } from '@/utils/request'
import {ref, reactive, toRefs, nextTick } from 'vue';
import { Button, Card, Row, Col, Form, FormItem, Select, SelectOption, Table, Modal, message, DropdownButton, Dropdown } from 'ant-design-vue';
import {customizedFilterOptions, isNumber, isInteger, labelDict, accAdd, accMinus, accMultiply} from '@/utils/my'
import _ from 'lodash'

// data
const loading = ref(false)
const visible = ref(false)
const searchTextForTraders = ref('')
const existData = ref([])
//// reactive+refs
const initFormData = {
    id: undefined,
    bill_date: '',
    bill_no: undefined,
    flight_no: undefined,
    departure_port: 'HGH',
    destination_port: undefined,
    //articles: 0,
    weight: 0,
    weight_for_fee: 0,
    unit_price: 0,
    id_trade_partner: undefined,
    bill_type: undefined,
    status: "0",
    total_amount: 0,
    memo: '',
    id_company: undefined,
    feeData: {},
    feeItems: []
}
const data = reactive({
  main: Object.assign({}, initFormData),
})
const { main } = toRefs(data);
const bill_type = ref("")
const confirmLoading = ref(false)
const formRef = ref(null); // 表单引用

//// constant
const dateFormat = 'YYYY-MM-DD'
const labelCol = {
  xs: { span: 24 },
  sm: { span: 10 }
}
const wrapperCol = {
  xs: { span: 24 },
  sm: { span: 14 }
}
const labelCol2 = {
  xs: { span: 20 },
  sm: { span: 6 }
}
// props
const props = defineProps({
    isAdmin:{
      type: Boolean,
      default: false
    },
    tradePartners: {
      type: Array,
      default: function(){
        return [];
      }
    },
    companies: {
      type: Array,
      default: function(){
        return [];
      }
    },
    ports: {
      type: Array,
      default: function(){
        return [];
      }
    },
    tradeObj: {
      type: Object,
      default: function(){
        return {};
      }
    },
    feeTypeById:{
      type: Object,
      default: function(){
        return {};
      }
    },
    dictProperties: {
      type: Object,
      default: function(){
        return {};
      }
    },
    url: {
      type: Object,
      default: function(){
        return {};
      }
    }
})

//// 表单验证规则
const validateNumber = (rule, value) => {
  //console.error("rule:",JSON.stringify(rule))
  if (_.isObject(value)) value = value.amount;
  if (!isNumber(value)) {
    return Promise.reject(`${rule.label}请输入数字！`);
  }
  return Promise.resolve(); // 验证通过
};
const validateInteger = (rule, value) => {
  if (!isInteger(value)) {
    return Promise.reject(`${rule.label}请输入整数！`);
  }
  return Promise.resolve(); // 验证通过
};
const formRules = reactive({
  feeData: {},
  total_amount: [
    { type: 'method', validator: validateNumber, trigger: 'blur', label: labelDict['total_amount']}
  ],
  weight_for_fee: [
    { type: 'method', validator: validateNumber, trigger: 'blur', label: labelDict['weight_for_fee']}
  ],
  weight: [
    { type: 'method', validator: validateNumber, trigger: 'blur', label: labelDict['weight']}
  ],
  unit_price: [
    { type: 'method', validator: validateNumber, trigger: 'blur', label: labelDict['unit_price']}
  ],
  articles: [
    { required: true, message: `${labelDict.articles}不能为空` },
    { type: 'method', validator: validateInteger, trigger: 'blur', label: labelDict['articles']}
  ],
  id_trade_partner: [
    { required: true, message:  `${labelDict.id_trade_partner}必选` }
  ],
  destination_port: [
    { required: true, message: `${labelDict.destination_port}目的港必选` }
  ],
  id_company: [
    { required: true, message: `${labelDict.id_company}入帐公司不能为空` }
  ],
  bill_type: [
    { required: true, message: `${labelDict.bill_type}必填` }
  ],
  bill_date: [
    { required: true, message: `${labelDict.bill_date}必填` }
  ],
  bill_no: [
    { required: true, message: `${labelDict.bill_no}必填`, trigger: 'blur' },
    { validator: (rule, value) => {
        // 由于有 required 规则，value为空这里理论上不会执行
        const regex = /^\d{11}$/;
        if (!value || regex.test(value)) {
          return Promise.resolve();
        } else {
          return Promise.reject(`${labelDict.bill_no}格式不正确，请输入11位数字！`);
        }
      },
      trigger: 'blur'
    }
  ]
})

// watch
watchEffect(()=>{
  // console.log("final main2:", JSON.stringify(main.value))
  main.value.feeItems = [];
  if(!main.value.id_trade_partner) {
    return;
  }
  let partner = props.tradePartners.find(r=>{
    return r.id === main.value.id_trade_partner;
  })
  if(partner) {
    main.value.id_company = partner.id_company
    let feeItems = partner.fee_items.split(",")
    // console.error("feeItems:", JSON.stringify(feeItems))
    feeItems.forEach((id)=>{
      let code = props.feeTypeById[id].value, name = props.feeTypeById[id].label;
      // 为每个费用动态添加规则
      formRules.feeData[code] =  [ //验证规则中的值，与验证结构对应用model结构绑定
        { validator: validateNumber, label: name, trigger: 'blur'}
      ]
      // 为每个费用动态表单对象
      main.value.feeItems.push({
        id, code, name
      })
      // 如果没有，为每个费用动态表单初始化值对象
      if(!main.value.feeData[code]){
          main.value.feeData[code] = {
            amount: 0, id, code, name
          }
      }
    })
    if(!main.value.feeItems || main.value.feeItems.length === 0) {
        message.error({content: `"${partner.name}"未设置费用科目，请前往贸易伙伴设置！`})
    }
  }
})

// computed
const title = computed(()=>{
  return main.value.id ? '编辑' : '新增'
})
const filteredTradObj = computed(() =>{
      let res = [], options = [];
      Object.entries(props.tradeObj).map(([key, value]) => {
              // console.error("key:", value.label, "value:", JSON.stringify(value))
              options= value.options.filter((v) => {
                // console.error("v.bill_type:",JSON.stringify(v.bill_type),typeof v.bill_type)
                return v.bill_type === parseInt(main.value.bill_type)
              });
              if (options.length > 0) {
                res.push({
                    label: value.label, options
                })
              }
      })
      // console.log("res:", res)
      return res
})

// methods
//// 重置表单
const resetForm = () => {
      setInitialValues()
};
// 设置新的初始值
const setInitialValues = () => {
      // 重置到新设置的值
      Object.assign(main.value, initFormData)
      // 清除校验结果
      formRef.value.resetFields();
      console.log('已设置新的初始值并重置');
};
function portFiltered(type) {
      let tmp = {};
      props.ports.forEach(r => {
          if (r['port_type'] && r['port_type'].indexOf(type) !== -1) {
            if (!tmp[r.country]) tmp[r.country] = [];
            tmp[r.country].push(r);
          }
      })
      return tmp;
}
function autoCompute(value){
      let total_amount = 0
      Object.values(main.value.feeData).forEach((f)=>{
       //console.error("f:",JSON.stringify(f))
        total_amount = accAdd(total_amount, f.amount||0)
      })
      main.value.total_amount = total_amount;
}
function computeFreight(){
      //console.error("calculate freight....")
      let weightForFee  = main.value.weight_for_fee
      let unitPrice = main.value.unit_price
      main.value.feeData['freight'].amount = accMultiply(weightForFee, unitPrice)
}
function dtChange(date, dateString) {
        console.log(date, dateString, main.value.bill_date);
        main.value.bill_date = dateString;
}
function m(dt,ft='YYYY-MM-DD'){
        if(!dt)return undefined;
        return moment(dt,ft);
}
function add() {
        console.log("add...")
        edit({});
}
async function edit(record) {
        //initialize
        visible.value = true
        console.log("record:", JSON.stringify(record))
        await nextTick(() => {
              setInitialValues()
              // console.log("record:", JSON.stringify(record))
              // console.log("dictProperties:", props.dictProperties)
              if(!_.isEmpty(record)){
                  console.log("load data...")
                  Object.assign(main.value, record) //edit的数据会指向保存，所以要重新验证
              }
              //console.log("final main:", JSON.stringify(main.value))
        })
}
const loadExistData = debounce(async function (event) {
        let bill_no = event.target.value;
        if (bill_no && bill_no.length > 7) {
          console.log("bill_no:", bill_no)
          let res = await postAction(props.url.getCheckBills, {bill_no})
          if(res) {
              existData.value = res.data.detail
              if (existData.value['id_company']) existData.value['id_company'] = parseInt(existData.value['id_company'])
          }
        }
        main.value.bill_type = undefined
      }, 300)
async function checkCreateOrUpdate(b_type){
      console.log("existData:", JSON.stringify(existData.value))
      if(b_type){
          if(existData.value && existData.value.length > 0){
              let r = existData.value.find((d) => d.bill_type === b_type)
              console.log("r:",r)
              // 存在完全相同数据，则提示编辑;否则为部分相同，加载部分数所
              if(r && b_type === 1){
                Modal.confirm({
                  title: '确认',
                  content: `"${r.bill_no}"的收入记录已存在,不能重复录入！是否要去修改原记录？`,
                  okText: '确定',
                  cancelText: '取消',
                  onOk() {
                     edit(r)
                  },
                  onCancel() {edit(pick(r,['bill_date']))},
                });
              }else{ //支出可以多条，所以相同主单号，也可能是不同的支付记录
                // 来回切换时，费用明细重置
                r = existData.value[0]
                let newData = Object.assign(
                    _.omit(r,['bill_date','unit_price', 'total_amount', 'status', 'memo', 'id_trade_partner','id', 'feeData', 'feeItems', 'id_company']),
                    _.pick(main.value, ['bill_type']) //后面对象优先, bill_date多次切，原bill_date会丢失
                )
                edit(newData)
              }
          }
      }
}
function close() {
      visible.value = false
}
function handleOk() {
  formRef.value
      .validate()
      .then(() => {
          console.log('values', toRaw(main.value));
          saveOrUpdate();
      })
      .catch(error => {
          message.warning("表单信息验证失败");
          console.log('error', error);
      });
}
const emit = defineEmits(['sync'])
async function saveOrUpdate(){
        //使用await,所在父函数必须用async
        //console.error(JSON.stringify(main.value))
        let res = await postAction(props.url.saveCheckBill, {...main.value, update_by: "admin"})
        if (res.success) {
           //if(!main.value.id) main.value.id = res.data.id
           message.success('保存成功')
           emit("sync",{id: main.value.id, opType: title.value})
           console.log("sync...")
           close()
        } else {
           message.error(`明细录保存失败`)
           console.error('错误原因', res.message)
        }
 }

defineExpose({ add, edit })
</script>
<style>

</style>
